package core;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.zip.GZIPOutputStream;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import core.db.DBConnectionUtil;
import core.util.CommUtils;
import core.util.Const;
import core.util.CoreDataUtil;
import core.util.DES;
import core.util.Unit;
import core.wrap.GZipRequestWrapper;
import core.wrap.InflateRequestWrapper;

/**
 * 拦截*.do
 * @author qiwx
 *
 */
@SuppressWarnings("unchecked")
public class CoreFileter implements Filter{
  private static Logger log = core.util.Logger.getLogger(CoreFileter.class);
  private CoreDao dao;
  @Override
  public void destroy() {
    CoreDataUtil.dataMap = null;
  }
  @Override
  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) 
           throws IOException, ServletException {
    dao = CoreDaoInvoke.getInstance();
    long s = System.currentTimeMillis();
    HttpServletRequest request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)resp;
    request.setCharacterEncoding("UTF-8");
    String callbackFunction = request.getParameter("callbackfun");//解决js跨域问题
    String ce = request.getHeader("Content-Encoding"); //用来解压
    String uri = request.getRequestURI();
    if ( ce != null ) {
  		if (ce.indexOf("deflate") >= 0 || ce.indexOf("inflate") >= 0) {
  			request = new InflateRequestWrapper(request);
  		} else if (ce.indexOf("gzip") >= 0) {
  			request = new GZipRequestWrapper(request);
  		}
    }
    String uriKey = uri;
    String methodName = "";
    HttpSession session = null;
    try {
      Unit unit = null;
      session = request.getSession();
      if ( CoreDataUtil.dataMap.containsKey( uriKey )) {
        unit = (Unit)CoreDataUtil.dataMap.get(uriKey);
      } else {
        throw new Exception("没有这个方法:"+ uriKey);
      }
      String classPath = unit.getClassPath();
      methodName = unit.getMethod();
      Class classIntance = Class.forName( classPath );
        Object classObject = classIntance.newInstance();   
        Method setRequestMethod = classIntance.getMethod("setRequest", HttpServletRequest.class);
        setRequestMethod.invoke(classObject, request);
        Method setResponseMethod = classIntance.getMethod("setResponse", HttpServletResponse.class);
        setResponseMethod.invoke(classObject, response);
        Method sessionMethod = classIntance.getMethod("setSession", HttpSession.class);
        sessionMethod.invoke(classObject, session);
        Method setDaoMethod = classIntance.getMethod("setDao", CoreDao.class);
        setDaoMethod.invoke(classObject, dao);
        Method method = classIntance.getMethod( methodName );//执行类中的方法
        Object obj = method.invoke(classObject);
        JSONObject returnObj = JSONObject.fromObject( (String)obj );
        String type = "";
        if ( returnObj.containsKey( Const.TYPE )) {
          type = returnObj.getString( Const.TYPE );
        } else {
          returnObj.put(Const.TYPE, DES.encodeOneKey(String.valueOf( Const.AJAX ), DES.key));
          type = DES.encodeOneKey(String.valueOf( Const.AJAX ), DES.key);
        }
        if ( DES.encodeOneKey(Const.AJAX+"", DES.key).equals( type ) ) {
          String obj2 = returnObj.getString(Const.DATA);
          if ( CommUtils.isNull(callbackFunction) ) {
            doResponse(obj2.toString(), request, response);
          } else {
            String callbackStr = callbackFunction + "(" + obj2.toString() + ")";
            doResponse(callbackStr, request, response);
          }
        } else if ( DES.encodeOneKey(Const.FORWORD+"", DES.key).equals(type) ) {
          if ( !returnObj.containsKey( Const.KEY ) || StringUtils.isEmpty(returnObj.getString( Const.KEY)) ) {
            throw new Exception("forword需要url,url不能为空");
          }
          String urlKey = returnObj.getString(Const.NAMESPACE) + "." + returnObj.getString( Const.KEY );
          request.getRequestDispatcher( (String)CoreDataUtil.dataMap.get(urlKey) ).forward(request, response);
        } else if ( DES.encodeOneKey(Const.REDIRECT+"", DES.key).equals(type) ) {
          if ( !returnObj.containsKey( Const.KEY ) || StringUtils.isEmpty(returnObj.getString( Const.KEY)) ) {
            throw new Exception("redirect需要url, url不能为空");
          }
          String urlKey = returnObj.getString(Const.NAMESPACE) + "." + returnObj.getString( Const.KEY );
          response.sendRedirect((String)CoreDataUtil.dataMap.get(urlKey));
       }
    } catch ( Exception e) {
      JSONObject obj = new JSONObject();
      obj.put(Const.STATE, "50000");
      obj.put(Const.ERRMSG, "系统错误");
      obj.put(Const.EXCEPTION, parseException(e));
      ajaxMethod(obj.toString(),  response);
      log.error("数据出错了=>", e);
    } finally {
    }
  }
  
  public String parseException( Exception e ) {
    return e.getStackTrace()[0].getFileName() + "的"
               + e.getStackTrace()[0].getMethodName() 
         + ":第"+ e.getStackTrace()[0].getLineNumber()
         + "行 "+ e.getLocalizedMessage() 
         + " "+ e.getCause();
  }

  @Override
  public void init(FilterConfig config) throws ServletException {
    dao = CoreDaoInvoke.getInstance();
    try {
      DBConnectionUtil.init();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  /**
   * ajax方法
   * 
   * @param messages
   * @throws Exception
   */
  public void ajaxMethod(String messages, HttpServletResponse response ){
    PrintWriter out = null;
    try {
      response.setContentType("text/html;charset=UTF-8");
      response.setHeader("Cache-Control", "no-cache");
      response.setCharacterEncoding("UTF-8");
      out = response.getWriter();
      out.print(String.valueOf(messages));
    } catch (Exception e) {
      log.error("ajaxMethod出错了=>", e);
    } finally {
      if (out != null) {
        out.flush();
        out.close();
      }
    }
  }
  public void doResposeInGZip( String data, HttpServletRequest request, 
	  	                                     HttpServletResponse response) throws IOException {
	  String ac = request.getHeader("Accept-Encoding");
    response.setContentType("text/html;charset=UTF-8");
    response.setHeader("Cache-Control", "no-cache");
    response.setCharacterEncoding("UTF-8");
	  byte[] result = null;
	  if ( !StringUtils.isEmpty(ac) ) {
		  if ( "gzip".equalsIgnoreCase(ac)) {
			  ByteArrayOutputStream out  =  new  ByteArrayOutputStream();  
			  GZIPOutputStream gout  =  new  GZIPOutputStream(out);  
			  gout.write(data.getBytes("UTF-8")); 
			  gout.close();  
			  result = out.toByteArray();
			  response.setHeader("Content-Encoding","gzip");  
			  response.setHeader("Content-Length", result.length+""); 
			  out.close();
		  }
	  }
	  response.getOutputStream().write( result );
  }
  
  public void doResponse( String data, HttpServletRequest request, 
		                        HttpServletResponse response) throws IOException {
	  String acceptEncode = request.getHeader("Accept-Encoding");//是否要求压缩
	  if ("gzip".equalsIgnoreCase(acceptEncode)) {
		  doResposeInGZip(data, request, response);
	  } else {
		  ajaxMethod( data, response ); 
	  }
  }
}
